Skip to content
Go back

ConcurrentModificationException 与 iterator

Published:  at  01:02 PM

ConcurrentModificationException 是 Java 集合框架中常见的运行时异常,主要在使用迭代器遍历集合时,检测到集合结构被修改而抛出

1. 产生原因

2. 常见情形

情形 1:单线程中错误修改集合

List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
for (String element : list) {  // 增强for循环使用迭代器
    if (element.equals("b")) {
        list.remove(element);  // 直接修改集合,modCount变化
    }
}
// 抛出ConcurrentModificationException

情形 2:多线程并发修改

List<String> list = new ArrayList<>();
// 线程1:遍历集合
new Thread(() -> {
    for (String element : list) {
        System.out.println(element);
        Thread.sleep(100);
    }
}).start();

// 线程2:修改集合
new Thread(() -> {
    Thread.sleep(200);
    list.add("d");  // 破坏线程1迭代器的一致性
}).start();

情形 3:错误使用子集合

List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
List<String> subList = list.subList(0, 2);  // 子集合与原集合共享数据
subList.add("x");  // 修改子集合会影响原集合的modCount
for (String s : list) {  // 遍历原集合时抛出异常
    System.out.println(s);
}

情形 4:迭代器混用

List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
Iterator<String> it1 = list.iterator();
Iterator<String> it2 = list.iterator();
it1.next();
it2.remove();  // 第二个迭代器修改集合,导致第一个迭代器失效
it1.next();    // 抛出异常

3. 注意事项与规范

正确删除元素的方式

多线程环境的安全措施

避免子集合与原集合混用

避免在循环中动态添加元素

4. 例外情况

总结

场景解决方案
单线程删除元素使用迭代器的 remove() 方法
多线程遍历与修改使用 CopyOnWriteArrayList 或同步
动态添加元素先收集到临时集合,迭代后合并
子集合操作复制数据到新集合,避免共享

哈哈下面的代码也能正常运行

@Test  
void test() {  
    List<String> a = new ArrayList<>();  
    a.add("1");  
    a.add("2");  
    a.add("3");  
    for (Iterator<String> iterator = a.iterator(); iterator.hasNext(); ) {  
        String next = iterator.next(); // cursor++  
        if ("1".equals(next)) {  
            a.remove(iterator.next()); // cursor++ && size--  
            a.remove(next); // size--  
            a.add(next); // size++  
            foo();  
        } // cursor == 2 && size == 2   
}  
}

Suggest Changes

Previous Post
JPA的1+N问题
Next Post
jersey提取各种形式的参数